package org.activequant.math.algorithms;

import org.apache.log4j.Logger;

/**
 * AR1 fitter that learns AR1 coefficients from maximizing the likelihood function.
 * To be specific, the answer maximizes the EMA-weighted likelihood functional.
 * <p>
 * For the reference:
 * <pre>
 *  X_{k + 1} - mu = Phi * (X_k - mu) + Sigma * epsilon_k 
 * </pre>
 * where X_k is price at k-th step. mu - mean value of price,
 * epsilon_k is uncorrelated "noise" term, Sigma - amplitude of the "noise".
 * <p>
 * Parameter Phi can be interpreted via correlation length Tau:
 * <pre>
 * Tau = -1 / ln(Phi)
 * </pre>
 * Note that certain data can result in Phi >= 1.0, which means "explosive" AR1 (unstable).
 * For explosive AR1 correlation length Tau does not have meaning, and is basically an infinity.<br/>
 * Holds the following associated variables:
 * <ul>
 * <li>regression(EMARegression)</li>
 * <li>prevValue(double)</li>
 * <li>firstTime(boolean)</li>
 * </ul>
 * <b>History:</b><br>
 *  - [09.02.2008] Created (Mike Kroutikov)<br>
 *
 *  @author Mike Kroutikov
 */
public class EMAAR1Fitter {
	
	@SuppressWarnings("unused")
	private Logger log = Logger.getLogger(getClass());
	/**
	 * private final EMARegression regression;
	 */
	private final EMARegression regression;
	/**
	 * constructs an EMAAR1Fitter using the given period(int) to initialize its associated regression(EMARegression)
	 * @param period
	 */
	public EMAAR1Fitter(int period) {
		regression = new EMARegression(period);
	}
	/**
	 * private double prevValue = 0.0;
	 */
	private double prevValue = 0.0;
	/**
	 * private boolean firstTime = true;
	 */
	private boolean firstTime = true;
	/**
	 * accumulates the given value(double) into its associated regression(EMARegression) if it is not the first one.
	 * @param value
	 */
	public void accumulate(double value) {
		if(firstTime) {
			firstTime = false;
		} else {
			regression.accumulate(value, prevValue);
		}
		prevValue = value;
	}
	/**
	 * returns the period(int) of the x(EMAAccumulator) of the associated regression(EMARegression)
	 * @return
	 */
	public int getPeriod() {
		return regression.getPeriod();
	}
	/**
	 * returns the numSamples(int) of the x(EMAAccumulator) of the associated regression(EMARegression)
	 * @return
	 */
	public int getNumSamples() {
		return regression.getNumSamples();
	}
	/**
	 * returns phi(double) as calculated by the associated regression(EMARegression)
	 * @return
	 */
	public double getPhi() {
		return regression.getPhi();
	}
	/**
	 * returns tau(double) as calculated by the associated regression(EMARegression)
	 * @return
	 */
	public double getTau() {
		return regression.getTau();
	}
	/**
	 * returns sigma(double) as calculated by the associated regression(EMARegression)
	 * @return
	 */
	public double getSigma() {
		return regression.getSigma();
	}
	/**
	 * returns mu(double) as calculated by the associated regression(EMARegression)
	 * @return
	 */
	public double getMu() {
		return regression.getMu();
	}
	/**
	 * returns isReady(boolean) as calculated by the associated regression(EMARegression)
	 * @return
	 */
	public boolean isReady() {
		return regression.isReady();
	}

	public String toString() {
		return "EMAAR1Fitter: period=" + getPeriod() + ", numSamples=" + getNumSamples() + ", mu=" + getMu() 
		+ ", phi=" + getPhi() + ", sigma=" + getSigma();
	}
}

